package com.multitrack.chromb;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;

import com.vecore.base.lib.utils.FileUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class OffScreenGreenScreenProcessor {

    private EGLDisplay mEglDisplay;
    private EGLContext mEglContext;
    private EGLSurface mEglSurface;
    private int mProgram;
    private int mTextureId;

    public void initialize(Context context, int width, int height) {
        initEGL(width, height);
        initGLComponents(context);
    }

    private int nOutWidth, nOutHeight;

    private final float[] vertices = {
            -1.0f, -1.0f, 0.0f,
            1.0f, -1.0f, 0.0f,
            -1.0f, 1.0f, 0.0f,
            1.0f, 1.0f, 0.0f
    };

    private final float[] textureCoords = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f
    };


    private FloatBuffer vertexBuffer;
    private FloatBuffer textureBuffer;

    private void initEGL(int width, int height) {
        nOutWidth = width;
        nOutHeight = height;
        mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
        int[] configAttribs = {
                EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
                EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
                EGL14.EGL_NONE
        };
        EGLConfig[] configs = new EGLConfig[1];
        int[] numConfigs = new int[1];
        EGL14.eglChooseConfig(mEglDisplay, configAttribs, 0, configs, 0, 1, numConfigs, 0);

        int[] contextAttribs = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE};
        mEglContext = EGL14.eglCreateContext(mEglDisplay, configs[0], EGL14.EGL_NO_CONTEXT, contextAttribs, 0);

        int[] surfaceAttribs = {EGL14.EGL_WIDTH, width, EGL14.EGL_HEIGHT, height, EGL14.EGL_NONE};
        mEglSurface = EGL14.eglCreatePbufferSurface(mEglDisplay, configs[0], surfaceAttribs, 0);
        EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
    }

    private void initGLComponents(Context context) {
        // 创建并编译着色器程序
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, FileUtils.readTxtFile(context, "asset:///dev/vert.txt"));
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FileUtils.readTxtFile(context, "asset:///dev/frag.txt"));
        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram, vertexShader);
        GLES20.glAttachShader(mProgram, fragmentShader);
        GLES20.glLinkProgram(mProgram);

        // 创建帧缓冲对象
//        int[] framebuffers = new int[1];
//        GLES20.glGenFramebuffers(1, framebuffers, 0);
//        mFramebuffer = framebuffers[0];


        vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        vertexBuffer.put(vertices).position(0);

        textureBuffer = ByteBuffer.allocateDirect(textureCoords.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        textureBuffer.put(textureCoords).position(0);
    }

    private int smoothnessHandle;
    private int similarityHandle;
    private int uResolutionLoc;
    private float smoothness = 0.1f;
    private float similarity = 0.1f; // 默认程度
    private int positionHandle;
    private int textureCoordHandle;
    private int textureHandle;
    private static final String TAG = "OffScreenGreenScreenPro";


    private int loadTexture(Bitmap bitmap) {
        int[] textureIds = new int[1];
        GLES20.glGenTextures(1, textureIds, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        return textureIds[0];
    }


    public Bitmap processBitmap(Bitmap input) {
        long st = System.currentTimeMillis();
        // 创建输入纹理
        mTextureId = loadTexture(input);


        // 设置视口并渲染
        GLES20.glViewport(0, 0, input.getWidth(), input.getHeight());
//        GLES20.glClearColor(1f, 0, 0, 0);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        GLES20.glUseProgram(mProgram);
        {

            textureHandle = GLES20.glGetUniformLocation(mProgram, "inputImageTexture");
            positionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
            textureCoordHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");

            similarityHandle = GLES20.glGetUniformLocation(mProgram, "similarity");
            smoothnessHandle = GLES20.glGetUniformLocation(mProgram, "smoothness");
            uResolutionLoc = GLES20.glGetUniformLocation(mProgram, "resolution");


            GLES20.glEnableVertexAttribArray(positionHandle);
            GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);

            GLES20.glEnableVertexAttribArray(textureCoordHandle);
            GLES20.glVertexAttribPointer(textureCoordHandle, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);

            Log.e(TAG, "onDrawFrame: " + this + positionHandle + " " + textureCoordHandle + " " + textureHandle + "" +
                    " " + smoothnessHandle + " " + similarityHandle + " similarity:" + similarity + " smoothness:" + smoothness);


            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
            GLES20.glUniform1i(textureHandle, 0);

            GLES20.glUniform2f(uResolutionLoc, nOutWidth, nOutHeight);  // 输入纹理分辨率
            GLES20.glUniform1f(similarityHandle, similarity);
            GLES20.glUniform1f(smoothnessHandle, smoothness);
        }
        // 执行绘制操作
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        GLES20.glDisableVertexAttribArray(positionHandle);
        GLES20.glDisableVertexAttribArray(textureCoordHandle);
        Log.e(TAG, "processBitmap: " + (System.currentTimeMillis() - st) + " ms");
        // 创建并返回处理后的Bitmap
        return saveFrame(input.getWidth(), input.getHeight());
    }

    public Bitmap saveFrame(int width, int height) {
        // Allocate a buffer to hold the pixel data
        ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * 4);
        buffer.order(ByteOrder.nativeOrder());

        // Read the pixels from the framebuffer
        GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);

        // Create a bitmap and copy the buffer data into it
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        buffer.rewind();
        bitmap.copyPixelsFromBuffer(buffer);

        // Flip the bitmap vertically
        Matrix matrix = new Matrix();
        matrix.preScale(1.0f, -1.0f);
        Bitmap bmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
        if (bmp != bitmap) {
            bmp.recycle();
        }
        return bmp;
    }


    private int loadShader(int type, String shaderCode) {
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

    public void release() {
        GLES20.glDeleteTextures(1, new int[]{mTextureId}, 0);
//        GLES20.glDeleteFramebuffers(1, new int[]{mFramebuffer}, 0);
        EGL14.eglDestroySurface(mEglDisplay, mEglSurface);
        EGL14.eglDestroyContext(mEglDisplay, mEglContext);
        vertexBuffer.clear();
        textureBuffer.clear();
    }
}